<?php

class Response {

    private static $instance = NULL;
    private $headerOnly = false;
    private $httpHeaders = array();
    private $cookies = array();
    private $contentType = 'text/html';
    private $charset = 'utf-8';
    private $compressContent = true;
    private $httpProtocol;
    protected $content = '';

    private function __construct() {
        
    }

    /**
     * @return Response
     */
    public static function getInstance() {
        if (self::$instance === NULL) {

            self::$instance = new Response ();
        }

        return self::$instance;
    }

    public function setHeaderOnly($value = true) {
        $this->headerOnly = (boolean) $value;
    }

    public function setLanguage($language = 'en') {
        $this->httpHeaders ['Content-language'] = 'en';
    }

    public function setCharset($charset = 'utf-8') {
        $this->charset = $charset;
    }

    public function setCompressContent($flag = true) {
        $this->compressContent = $flag;
    }

    public function setHttpProtocol($httpProtocol) {
        if ($httpProtocol) {
            $this->httpProtocol = $httpProtocol;
        }
    }

    public function setStatusCode($statusCode) {
        if ($statusCode) {
            $this->statusCode = $statusCode;
        }
    }

    public function setStatusText($statusText) {
        if ($statusText) {
            $this->statusCode = $statusText;
        }
    }

    public function setContentType($contentType = 'text/html') {

        $this->contentType = $contentType;
    }

    public function setHttpHeader($name, $value) {
        if (null === $value) {
            unset($this->httpHeaders [$name]);

            return;
        }
        $this->httpHeaders [$name] = $value;
    }

    public function getHttpHeader($name) {
        $name = $this->normalizeHeaderName($name);

        return isset($this->httpHeaders [$name]) ? $this->httpHeaders [$name] : 'not set';
    }

    public function clearHttpHeaders() {
        $this->httpHeaders = array();
    }

    protected function normalizeHeaderName($name) {
        return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", strtr(ucfirst(strtolower($name)), '_', '-'));
    }

    public function hasHttpHeader($name) {
        return array_key_exists($this->normalizeHeaderName($name), $this->httpHeaders);
    }

    public function removeHttpHeader($name) {
        $name = $this->normalizeHeaderName($name);

        if (isset($this->httpHeaders [$name])) {
            unset($this->httpHeaders [$name]);
        }
    }

    public function setCookie($name, $value, $expire = null, $path = '/', $domain = '', $secure = false, $httpOnly = false, $raw = false) {
        if ($expire !== null) {
            if (is_numeric($expire)) {
                $expire = (int) $expire;
            } else {
                $expire = strtotime($expire);
                if ($expire === false || $expire == - 1) {
                    throw new Exception('Your expire parameter is not valid.');
                }
            }
        }

        $this->cookies [] = array('name' => $name, 'value' => $value, 'expire' => $expire, 'path' => $path, 'domain' => $domain, 'secure' => $secure ? true : false, 'httpOnly' => $httpOnly, 'raw' => $raw);
    }

    public function compressContent($content) {
        $httpAcceptEncoding = $_SERVER ['HTTP_ACCEPT_ENCODING'];
        if (headers_sent()) {
            $encoding = false;
        } elseif (strpos($httpAcceptEncoding, 'x-gzip') !== false) {
            $encoding = 'x-gzip';
        } elseif (strpos($httpAcceptEncoding, 'gzip') !== false) {
            $encoding = 'gzip';
        } else {
            $encoding = false;
        }

        if ($encoding) {
            header('Content-Encoding: ' . $encoding);
            $size = strlen($content);
            //$content = gzcompress ( $content, 9 );
            $content = ob_gzhandler($content, 5);
            //$content = substr ( $content, 0, $size );
        }
        return $content;
    }

    private function sendHttpHeaders() {

        if (substr(php_sapi_name(), 0, 3) == 'cgi') {
            // fastcgi servers cannot send this status information because it was sent by them already due to the HTT/1.0 line
            // so we can safely unset them. see ticket #3191
            unset($this->httpHeaders ['Status']);
        }

        $this->httpHeaders ['Content-Type'] = $this->contentType . '; charset=' . $this->charset;

        foreach ($this->httpHeaders as $name => $value) {
            if ($value) {
                header($name . ': ' . $value);
            }
        }
        $status = $this->httpProtocol . ' ' . $this->statusCode . ' ' . $this->statusText;
        header($status);
    }

    private function sendCookies() {
        foreach ($this->cookies as $cookie) {
            if (version_compare(phpversion(), '5.2', '>=')) {
                if ($cookie['raw'])
                    setrawcookie($cookie ['name'], $cookie ['value'], $cookie ['expire'], $cookie ['path'], $cookie ['domain'], $cookie ['secure'], $cookie ['httpOnly']);
                else
                    setcookie($cookie ['name'], $cookie ['value'], $cookie ['expire'], $cookie ['path'], $cookie ['domain'], $cookie ['secure'], $cookie ['httpOnly']);
            }
            else {
                if ($cookie['raw'])
                    setrawcookie($cookie ['name'], $cookie ['value'], $cookie ['expire'], $cookie ['path'], $cookie ['domain'], $cookie ['secure']);
                else
                    setcookie($cookie ['name'], $cookie ['value'], $cookie ['expire'], $cookie ['path'], $cookie ['domain'], $cookie ['secure']);
            }
        }
    }

    public function send() {


        $this->sendHttpHeaders();
        $this->sendCookies();
        if ($this->headerOnly) {
            return;
        }
        if (Utility::isAjaxRequest()) {

            $content = $this->content;
        } else {
            $content = Page::getInstance(__APPLICATION__)->getDocument();
        }
        if ($this->compressContent) {

            $content = $this->compressContent($content);
        }

        echo $content;
    }

    public function redirect($url) {
        header('Location: ' . $url);
        exit;
    }

    public function setContent($content, $mode = 'w') { //mode w: for wrting from the beginning, p: for prepend, a: for append content

        if (Utility::isAjaxRequest()) {
            switch ($mode) {
                case 'a' :
                    $this->content = $content . $this->content;
                    break;
                case 'p' :
                    $this->content = $this->content . $content;
                    break;
                case 'w' :
                default :
                    $this->content = $content;
                    break;
            }
        } else {
            Page::getInstance()->setContent($content, $mode);
        }
    }

    public function appendContent($content) {
        $this->setContent($this->getContent(), 'a');
    }

    public function prependContent($content) {
        $this->setContent($content, 'p');
    }

    public function clearContent() {
        $this->content = '';
    }

}

?>